package com.xykj.service.impl;

import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.xykj.common.entry.HkFundFlow;
import com.xykj.mapper.HKFundFlowMapper;
import com.xykj.service.FCrawlerService;
import com.xykj.web.websocket.NewsWebSocketHandler;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 港股通资金流爬虫类
 */
@Slf4j
@Service
public class HkFundFlowCrawlerService implements FCrawlerService {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private HKFundFlowMapper hkFundFlowMapper;

    @Autowired
    private NewsWebSocketHandler webSocketHandler;

    private String apiUrl = "https://push2.eastmoney.com/api/qt/kamt/get?fields1=f1,f2,f3,f4&fields2=f51,f52,f53,f54,f56,f60,f61,f62,f63,f65,f66" +
            "&ut=fa5fd1943c7b386f172d6893dbfba10b&cb=jQuery1123015864081307257227_%s&_=%s";

    /**
     * 港股通资金流向爬虫服务
     * <p>
     * 实现步骤：
     * 1. 使用Jsoup定时请求东方财富网API获取JSONP数据。
     * 2. 解析返回的JSONP数据，使用Gson提取港股通资金流向信息。
     * 3. 批量删除旧数据并插入新数据到数据库。
     * 4. 通过WebSocket广播最新数据给前端。
     * <p>
     * 关键点：动态时间戳URL、JSONP解析、批量数据库操作、定时任务、WebSocket推送。
     */

    @Override
    @Scheduled(fixedRate = 60000)
    @Transactional(rollbackFor = Exception.class)
    public boolean crawl() {
        log.info("开始爬取港股通资金流...");
        try {
            apiUrl = getFullApiUrl();
            // 1. 发送HTTP请求获取JSONP数据
            String jsonpResponse = Jsoup.connect(apiUrl)
                    .ignoreContentType(true)
                    .execute()
                    .body();
            // 2. 提取JSON部分（去掉JSONP包装）
            String json = jsonpResponse.substring(
                    jsonpResponse.indexOf('(') + 1,
                    jsonpResponse.lastIndexOf(')')
            );
            // 3. 使用Gson解析JSON
            JsonObject jsonObject = JsonParser.parseString(json).getAsJsonObject();
            JsonObject data = jsonObject.getAsJsonObject("data");
            List<HkFundFlow> hkFundFlows = parseHkFundFlow(data);
            if (hkFundFlows.isEmpty()) {
                log.warn("未解析到有效的港股通资金流向数据");
                return false;
            }
            List<Long> longs = hkFundFlowMapper.selectExistingIds();
            if (!longs.isEmpty()) {
                hkFundFlowMapper.batchDelete(longs);
            }
            // 批量插入新数据
            hkFundFlowMapper.batchInsert(hkFundFlows);
            // WebSocket推送
            webSocketHandler.broadcast(hkFundFlows);
            log.info("成功更新 {} 条爬取港股通数据", hkFundFlows.size());
        } catch (IOException e) {
            log.error("获取港股通资金流向数据失败: {}", e.getMessage(), e);
            return false;
        }
        return true;
    }

    private List<HkFundFlow> parseHkFundFlow(JsonObject data) {
        List<HkFundFlow> result = new ArrayList<>();
        LocalDateTime now = LocalDateTime.now();// 当前时间用于createTime和updateTime
        Map<String, String> sectorNames = new HashMap<>();
        sectorNames.put("hk2sh", "港股通(沪)");
        sectorNames.put("sh2hk", "沪股通");
        sectorNames.put("hk2sz", "港股通(深)");
        sectorNames.put("sz2hk", "深股通");
        // 遍历四个市场方向
        for (String key : sectorNames.keySet()) {
            if (data.has(key)) {
                JsonObject item = data.getAsJsonObject(key);
                HkFundFlow flow = new HkFundFlow();
                // 设置板块名称
                flow.setBoardName(sectorNames.get(key));
                // 设置资金余额（使用dayAmtRemain字段）
                flow.setBalance(BigDecimal.valueOf(item.get("buySellAmt").getAsDouble()));
                // 设置成交净买额（使用netBuyAmt字段）
                flow.setNetBuy(BigDecimal.valueOf(item.get("netBuyAmt").getAsDouble()));
                // 设置当日资金限额（使用dayAmtThreshold字段）
                flow.setQuota(BigDecimal.valueOf(item.get("dayAmtThreshold").getAsDouble()));
                // 设置创建时间和更新时间
                flow.setCreatedAt(now);
                flow.setUpdatedAt(now);
                result.add(flow);
            }
        }
        return result;
    }

    // 获取完整的URL，包含动态生成的时间戳
    public String getFullApiUrl() {
        long timestamp = System.currentTimeMillis();
        // 为两个时间戳参数使用相同的值
        return String.format(apiUrl, timestamp, timestamp);
    }
}